package com.soo.hoo.admin.config;

import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * mp配置文件
 * </p>
 *
 * @author 杨燚
 * @since 2022/2/18
 */
@Slf4j
@Configuration
@MapperScan("com.soo.hoo.admin.mapper")
public class MybatisPlusConfig {

    /**
     * 分页插件
     *
     * @return MybatisPlusInterceptor
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //如果是不同类型的库，请不要指定DbType，其会自动判断。
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }

    /**
     * 元对象处理程序，数据库插入或更新数据时，给实体对象公共字段添加默认值；
     * 注意，需要在公共字段上添加{@code @TableField(fill = FieldFill.INSERT)}或{@code @TableField(fill = FieldFill.INSERT_UPDATE)}注解；
     * modifyAt和modifyBy字段在插入和更新时都需要填充值，所以是INSERT_UPDATE。
     *
     * @return 元对象处理程序
     */
    @Bean
    public MetaObjectHandler metaObjectHandler() {
        return new MetaObjectHandler() {
            @Override
            public void insertFill(MetaObject metaObject) {
                long userId;
                try {
                    userId = StpUtil.getLoginId(1L);
                } catch (SaTokenException e) {
                    log.warn("获取用户登录信息失败，登录id将默认为【1】，除数据初始化操作以外该操作应不被允许。");
                    userId = 1L;
                }
                LocalDateTime now = LocalDateTime.now();
                this.strictInsertFill(metaObject, "createAt", LocalDateTime.class, now);
                this.strictInsertFill(metaObject, "createBy", Long.class, userId);
                this.strictInsertFill(metaObject, "modifyAt", LocalDateTime.class, now);
                this.strictInsertFill(metaObject, "modifyBy", Long.class, userId);
            }

            @Override
            public void updateFill(MetaObject metaObject) {
                long userId;
                try {
                    userId = StpUtil.getLoginId(1L);
                } catch (SaTokenException e) {
                    log.warn("获取用户登录信息失败，登录id将默认为【1】，除数据初始化操作以外该操作应不被允许。");
                    userId = 1L;
                }
                LocalDateTime now = LocalDateTime.now();
                this.strictUpdateFill(metaObject, "modifyBy", Long.class, userId);
                this.strictUpdateFill(metaObject, "modifyAt", LocalDateTime.class, now);
            }
        };
    }

    /**
     * sql注入器
     * 在原来默认的sql注入器里又添加批量插入记录的方法
     *
     * @return sql注入器
     */
    @Bean
    public DefaultSqlInjector defaultSqlInjector() {
        return new DefaultSqlInjector() {
            @Override
            public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
                List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
                // 注入批量插入的方法，源码里本就有批量插入的方法，只是在默认的sql注入器里没有注入
                methodList.add(new InsertBatchSomeColumn());
                return methodList;
            }
        };
    }
}
